package com.kexio.core.security.context;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 用户上下文持有者 - 基于ThreadLocal实现
 *
 * @author Kexio Team
 * @since 1.0.0
 */
public class UserContextHolder {

    private static final Logger log = LoggerFactory.getLogger(UserContextHolder.class);

    /**
     * 使用ThreadLocal保存当前线程的用户上下文
     */
    private static final ThreadLocal<UserContext> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 使用InheritableThreadLocal保存父线程的用户上下文(用于异步任务)
     */
    private static final InheritableThreadLocal<UserContext> INHERITABLE_CONTEXT_HOLDER = new InheritableThreadLocal<>();

    /**
     * 默认使用普通ThreadLocal
     */
    private static boolean inheritableContext = false;

    /**
     * 获取当前用户上下文
     *
     * @return 用户上下文
     */
    public static UserContext getContext() {
        UserContext context = inheritableContext ? 
                INHERITABLE_CONTEXT_HOLDER.get() : CONTEXT_HOLDER.get();
        return context;
    }

    /**
     * 设置当前用户上下文
     *
     * @param userContext 用户上下文
     */
    public static void setContext(UserContext userContext) {
        if (userContext == null) {
            clear();
            return;
        }

        if (inheritableContext) {
            INHERITABLE_CONTEXT_HOLDER.set(userContext);
        } else {
            CONTEXT_HOLDER.set(userContext);
        }

        log.debug("设置用户上下文: userId={}, username={}", 
                userContext.getUserId(), userContext.getUsername());
    }

    /**
     * 清除当前用户上下文
     */
    public static void clear() {
        CONTEXT_HOLDER.remove();
        INHERITABLE_CONTEXT_HOLDER.remove();
        log.debug("已清除用户上下文");
    }

    /**
     * 获取当前用户ID
     *
     * @return 用户ID
     */
    public static Long getCurrentUserId() {
        UserContext context = getContext();
        return context != null ? context.getUserId() : null;
    }

    /**
     * 获取当前用户名
     *
     * @return 用户名
     */
    public static String getCurrentUsername() {
        UserContext context = getContext();
        return context != null ? context.getUsername() : null;
    }

    /**
     * 获取当前用户昵称
     *
     * @return 用户昵称
     */
    public static String getCurrentNickname() {
        UserContext context = getContext();
        return context != null ? context.getNickname() : null;
    }

    /**
     * 获取当前租户ID
     *
     * @return 租户ID
     */
    public static Long getCurrentTenantId() {
        UserContext context = getContext();
        return context != null ? context.getTenantId() : null;
    }

    /**
     * 获取当前部门ID
     *
     * @return 部门ID
     */
    public static Long getCurrentDeptId() {
        UserContext context = getContext();
        return context != null ? context.getDeptId() : null;
    }

    /**
     * 检查当前用户是否拥有指定角色
     *
     * @param role 角色
     * @return 是否拥有
     */
    public static boolean hasRole(String role) {
        UserContext context = getContext();
        return context != null && context.hasRole(role);
    }

    /**
     * 检查当前用户是否拥有任意指定角色
     *
     * @param roles 角色列表
     * @return 是否拥有任意一个
     */
    public static boolean hasAnyRole(String... roles) {
        UserContext context = getContext();
        return context != null && context.hasAnyRole(roles);
    }

    /**
     * 检查当前用户是否拥有指定权限
     *
     * @param permission 权限
     * @return 是否拥有
     */
    public static boolean hasPermission(String permission) {
        UserContext context = getContext();
        return context != null && context.hasPermission(permission);
    }

    /**
     * 检查当前用户是否拥有任意指定权限
     *
     * @param permissions 权限列表
     * @return 是否拥有任意一个
     */
    public static boolean hasAnyPermission(String... permissions) {
        UserContext context = getContext();
        return context != null && context.hasAnyPermission(permissions);
    }

    /**
     * 检查当前用户是否拥有全部指定权限
     *
     * @param permissions 权限列表
     * @return 是否拥有全部
     */
    public static boolean hasAllPermissions(String... permissions) {
        UserContext context = getContext();
        return context != null && context.hasAllPermissions(permissions);
    }

    /**
     * 检查当前用户是否为超级管理员
     *
     * @return 是否为超级管理员
     */
    public static boolean isAdmin() {
        UserContext context = getContext();
        return context != null && context.isAdmin();
    }

    /**
     * 检查当前线程是否有用户上下文
     *
     * @return 是否有用户上下文
     */
    public static boolean hasContext() {
        return getContext() != null;
    }

    /**
     * 以指定用户身份执行任务
     *
     * @param userContext 用户上下文
     * @param task        任务
     * @param <T>         返回值类型
     * @return 任务执行结果
     */
    public static <T> T runAs(UserContext userContext, java.util.function.Supplier<T> task) {
        UserContext originalContext = getContext();
        try {
            setContext(userContext);
            return task.get();
        } finally {
            setContext(originalContext);
        }
    }

    /**
     * 以指定用户身份执行任务(无返回值)
     *
     * @param userContext 用户上下文
     * @param task        任务
     */
    public static void runAs(UserContext userContext, Runnable task) {
        runAs(userContext, () -> {
            task.run();
            return null;
        });
    }

    /**
     * 设置是否使用可继承的上下文(用于异步任务)
     *
     * @param inheritable 是否可继承
     */
    public static void setInheritableContext(boolean inheritable) {
        inheritableContext = inheritable;
    }

    /**
     * 是否使用可继承的上下文
     *
     * @return 是否可继承
     */
    public static boolean isInheritableContext() {
        return inheritableContext;
    }

    /**
     * 创建上下文快照
     *
     * @return 上下文快照
     */
    public static UserContext createSnapshot() {
        UserContext current = getContext();
        if (current == null) {
            return null;
        }

        // 创建一个副本，避免原始对象被修改
        return UserContext.builder()
                .userId(current.getUserId())
                .username(current.getUsername())
                .nickname(current.getNickname())
                .email(current.getEmail())
                .phone(current.getPhone())
                .avatar(current.getAvatar())
                .tenantId(current.getTenantId())
                .tenantName(current.getTenantName())
                .deptId(current.getDeptId())
                .deptName(current.getDeptName())
                .roles(current.getRoles())
                .permissions(current.getPermissions())
                .loginTime(current.getLoginTime())
                .loginIp(current.getLoginIp())
                .sessionId(current.getSessionId())
                .isAdmin(current.getIsAdmin())
                .attributes(current.getAttributes())
                .build();
    }
}
